package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

func main() {
	if len(os.Args)>=3{
		fmt.Printf("arg:%v\n",os.Args)
		_op:=os.Args[1]
		_path:=os.Args[2]
		fmt.Printf("start.....\n")
		if err:=bomStart(strings.ToLower(_op)=="add",_path);err!=nil{
			fmt.Printf("err error:%s",err.Error())
		}
		fmt.Printf("end.....\n")
		return
	}

	fmt.Printf("please\n")
	_reader := bufio.NewReader(os.Stdin)
	for {
		_data, _, err := _reader.ReadLine()
		if err != nil {
			fmt.Printf("readLineErr:%s\n", err.Error())
			continue
		}
		_str := string(_data)
		_strs := strings.Split(_str, " ")
		if len(_strs) == 0 {
			continue
		}
		isAdd := true
		switch strings.ToLower(_strs[0]) {
		case "add":
			break
		case "remove":
			isAdd = false
			break
		default:
			fmt.Printf("no do any...\n")
			continue
		}
		_path := _strs[1]
		fmt.Printf("start......\n")
		if err=bomStart(isAdd,_path);err!=nil{
			fmt.Printf("err error:%s",err.Error())
		}
		fmt.Printf("end.......\n")

	}
}
func bomStart(isAdd bool,_path string)error{
	_finfo, err := os.Stat(_path)
	if err != nil {
		return err
	}
	if _finfo.IsDir() {
		filepath.Walk(_path, func(filename string, fi os.FileInfo, err error) error {
			if !fi.IsDir() {
				if err := bom(isAdd, filename); err != nil {
					fmt.Printf("err fiel:%s,error:%s\n", fi.Name(), err.Error())
				}
			}
			return nil
		})
	} else {
		return bom(isAdd, _path)
	}
	return nil
}
func bom(isAdd bool, _path string) error {
	_file, err := os.OpenFile(_path, os.O_RDWR, 0666)
	if err != nil {
		return err
	}
	defer _file.Close()
	_tmpFiel, err := ioutil.TempFile("", "dd")
	if err != nil {
		return err
	}
	defer func() {
		_tmpFiel.Close()
		os.Remove(_tmpFiel.Name())
	}()
	bom := []byte{0xEF, 0xBB, 0xBF}
	_bytes := []byte{0x00, 0x00, 0x00}
	_size, err := _file.Read(_bytes)
	_,err=_file.Seek(0,os.SEEK_SET)
	if err!=nil{
		return err
	}
	if err != nil {
		return err
	}
	if _size != 3 {
		return errors.New("no bom field")
	}
	isBom := true
	for i := 0; i < 3; i++ {
		if _bytes[i] != bom[i] {
			isBom = false
			break
		}
	}
	if isAdd && !isBom {
		fmt.Printf("%s add bom\n",_path)
		_, err := _tmpFiel.Write(bom)
		if err != nil {
			return err
		}
	} else if isBom && !isAdd {
		fmt.Printf("%s remove bom\n",_path)
		_, err = _file.Seek(3, os.SEEK_SET)
		if err != nil {
			return err
		}
	}else {
		return nil
	}
	err = copy(_tmpFiel, _file)
	if err = _file.Truncate(0); err != nil {
		return err
	}
	if _, err = _tmpFiel.Seek(0, os.SEEK_SET); err != nil {
		return err
	}
	if _, err = _file.Seek(0, os.SEEK_SET); err != nil {
		return err
	}

	if err = copy(_file, _tmpFiel); err != nil {
		return err
	}

	return _file.Sync()
}
func printseek(file *os.File) {
	_ss, _ := file.Seek(0, os.SEEK_CUR)
	fmt.Printf("file:%s,seek:%d\n", file.Name(), _ss)
}
func copy(dest, source *os.File) error {
	var err error
	_buf := make([]byte, 1024)
	_size := 0
	for {
		printseek(dest)
		printseek(source)
		_size, err = source.Read(_buf)
		if err != nil && err != io.EOF {
			return err
		}
		dest.Write(_buf[:_size])
		if io.EOF == err {
			return nil
		}
	}
}
func repair(sourDir,targetDir string){
	/*filepath.Abs(sourDir)
	sourDir:=filepath.Dir(sourDir)
	targetDir:=filepath.Dir(targetDir)*/
	filepath.Walk(sourDir,func(filename string, fi os.FileInfo, err error) error {

		return nil
	})
}
